/*
 * @(#)NateOnMessenger.java
 *
 * Copyright (c) 1998-2005 Jang-Ho Hwang, 
 * All Rights Reserved.
 *
 * $Id: NateOnMessenger.java,v 1.1.1.1 2005/05/22 01:02:27 rath Exp $
 */
package rath.nateon;

import rath.nateon.event.NateOnAdapter;
import rath.nateon.event.NateOnListener;
import java.io.IOException;
import java.util.Vector;
/**
 * 네이트온 메신져 클래스
 * 
 * @author Jang-Ho Hwang, rath@xrath.com
 * @version 1.0.000, 2005/05/20
 */
public class NateOnMessenger 
{
	private String userid = null;
	private String password = null;

	boolean isLoginProgress = false;
	boolean isLoggedIn = false;

	private DispatchChannel dispatch;
	NotificationChannel notification;

	private Vector l = new Vector();
	private boolean isAutoAccept = false;

	public NateOnMessenger()
	{

	}

	public NateOnMessenger( String userid, String password )
	{
		setAuthInfo( userid, password );
	}

	public void setAuthInfo( String id, String pass )
	{
		this.userid = id;
		this.password = pass;
	}

	public String getUserId()
	{
		return this.userid;
	}

	public String getPassword()
	{
		return this.password;
	}

	/**
	 * 네이트온에서 DES라고 주장하는 NateEncode를 수행하여
	 * 비밀번호를 암호화해준다.
	 */
	public String getEncodedPassword()
	{
		return new NateEncode().encode(password);
	}

	/**
	 * 로그인 할 것을 명령한다.
	 */
	public void login()
	{
		isLoginProgress = true;
		// 로그인 에러시 progress를 false로 해주어야 한다.

		this.dispatch = new DispatchChannel(this, "dpl.nate.com:5004");
		this.dispatch.start();
	}

	public void loginWait() throws InterruptedException
	{
		final Object lock = new Object();
		NateOnAdapter temp = new NateOnAdapter() {
			public void loginComplete( NateUser me )
			{
				shoot();
			}
			public void loginFailed()
			{
				shoot();
			}
			private void shoot() 
			{
				synchronized(lock)
				{
					lock.notify();
				}
			}
		};
		addNateOnListener( temp );
		login();
		
		synchronized(lock)
		{
			lock.wait();
		}
		removeNateOnListener( temp );
	}

	/**
	 * 현재 로그인중인지 확인한다.
	 */
	public boolean isLoginProgress()
	{
		return this.isLoginProgress;
	}

	/**
	 * 로그인 되어있는지 확인한다.
	 */
	public boolean isLoggedIn()
	{
		return this.isLoggedIn;
	}

	public NotificationChannel getNotificationChannel()
	{
		return this.notification;
	}

	public void setAutoAccept( boolean autoAccept )
	{
		this.isAutoAccept = autoAccept;
	}

	public boolean isAutoAccept()
	{
		return this.isAutoAccept;
	}

	/**
	 * 자기 자신의 NateUser 객체를 가져온다. 이것은 로그인이 완전히 끝날때까지
	 * 언제나 null 을 반환할 것이다.
	 */
	public NateUser getOwner()
	{
		return this.notification.getOwner();
	}

	/**
	 * 특정 대화상대와 메시지를 주고받기 위해 채널을 생성한다.
	 * 생성된 채널은 channelCreated 이벤트로 전달된니 이 후에 초대하라.
	 */
	public void createChannel() throws IOException
	{
		notification.createChannel();
	}

	/**
	 * 해당 사용자를 찾아서 리턴하는 함수로 동기 메서드이다.
	 */
	public ChatChannel callAndInvite( final String email ) 
		throws IOException, InterruptedException
	{
		final WrappedChatChannel channel = new WrappedChatChannel();
		final Object lock = new Object();

		NateOnListener temp = new NateOnAdapter() {
			String sessionId = null;
			public void channelOpened( ChatChannel chan ) throws IOException
			{
				sessionId = chan.getSessionId();
				invite( chan, email );
			}
			public void channelJoined( ChatChannel chan, NateUser user ) throws IOException
			{
				if( sessionId!=null && chan.getSessionId().equals(sessionId) &&
					user.getEmail().equals(email) )
				{
					channel.channel = chan;
					synchronized(lock)
					{
						lock.notify();
					}
				}
			}
			public void channelCancel( ChatChannel chan ) throws IOException
			{
				if( sessionId!=null && chan.getSessionId().equals(sessionId) )
				{
					synchronized(lock)
					{
						lock.notify();
					}					
				}
			}
		};
		addNateOnListener( temp );
		createChannel();
		synchronized(lock)
		{
			lock.wait(20000);
		}
		removeNateOnListener( temp );
		return channel.channel;
	}

	class WrappedChatChannel
	{
		ChatChannel channel;
	}

	public void invite( ChatChannel chat, String email ) throws IOException
	{
		notification.invite( chat, email );
	}

	public void sendSMS( String to, String msg ) throws IOException
	{
		notification.sendSMS(to, msg);
	}

	public void addNateOnListener( NateOnListener l )
	{
		if( !this.l.contains(l) )
			this.l.add( l );
	}

	public void removeNateOnListener( NateOnListener l )
	{
		this.l.removeElement(l);
	}

	void fireLoginComplete( NateUser me ) 
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			n.loginComplete(me);
		}
	}

	void fireLoginFailed()
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			n.loginFailed();
		}
	}

	void fireWhoAddMe( NateUser user )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.whoAddMe(user);
			}
			catch( IOException e ) { e.printStackTrace(); }
		}
	}

	void fireWhoRemoveMe( NateUser user )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.whoRemoveMe(user);
			}
			catch( IOException e ) { e.printStackTrace(); }
		}
	}

	void fireChannelOpened( ChatChannel chan )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.channelOpened(chan);
			}
			catch( IOException e ) { e.printStackTrace(); }
		}
	}

	void fireChannelMessage( ChatChannel chan, String from, String font, String msg )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.channelMessage(chan, from, font, msg);
			}
			catch( IOException e ) { e.printStackTrace(); }
		}
	}

	void fireChannelClosed( ChatChannel chan )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.channelClosed(chan);
			}
			catch( IOException e ) { e.printStackTrace(); }
		}
	}

	void fireChannelCreated( ChatChannel chan )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.channelCreated(chan);
			}
			catch( IOException e ) { e.printStackTrace(); }
		}
	}

	void fireChannelJoined( ChatChannel chan, NateUser user )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.channelJoined(chan, user);
			}
			catch( IOException e ) { e.printStackTrace(); }
		}
	}

	void fireChannelParted( ChatChannel chan, NateUser user )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.channelParted(chan, user);
			}
			catch( IOException e ) { e.printStackTrace(); }
		}
	}

	void fireChannelCancel( ChatChannel chan )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.channelCancel(chan);
			}
			catch( IOException e ) { e.printStackTrace(); }
		}
	}

	void fireSMSReceived( String from, String to, String msg )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.smsReceived(from, to, msg);
			}
			catch( Exception e ) { e.printStackTrace(); }
		}
	}

	void fireServerClosed()
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.serverClosed();
			}
			catch( Exception e ) { e.printStackTrace(); }
		}
	}

	void fireServerAborted( Exception error )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.serverAborted(error);
			}
			catch( Exception e ) { e.printStackTrace(); }
		}
	}

	void fireConnectFailed( Exception error )
	{
		for(int i=l.size()-1; i>=0; i--)
		{
			NateOnListener n = (NateOnListener)l.get(i);
			try
			{
				n.connectFailed(error);
			}
			catch( Exception e ) { e.printStackTrace(); }
		}
	}

	public static void main( String[] args ) throws Exception
	{
		final NateOnMessenger nateon = new NateOnMessenger();
		nateon.setAutoAccept( true );
		nateon.setAuthInfo( "danmuji-ck@nate.com", "leappass" );
		nateon.loginWait();
		nateon.addNateOnListener( new NateOnAdapter() {
			public void channelMessage( ChatChannel chat, String font, String msg ) 
				throws IOException
			{
				System.out.println( "----------------------" );
				System.out.println( msg );
				System.out.println( "----------------------" );
			}
		});

		ChatChannel chat = nateon.callAndInvite( "xrath@lycos.co.kr" );
		if( chat!=null )
		{
			chat.sendMessage( "안녕 으흐흐흐 /만족/" );
		}
	}
}
